#include <linux/clk.h>
#include <linux/clk/sunxi.h>

#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/scatterlist.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/reset.h>

#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/of_platform.h>

#include <linux/mmc/host.h>
#include <linux/mmc/sd.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/core.h>
#include <linux/mmc/card.h>
#include <linux/mmc/slot-gpio.h>

#ifndef __SUNXI_MMC_H__
#define __SUNXI_MMC_H__


#define DRIVER_NAME "sunxi-smhc"
#define DRIVER_RIVISION "v0.6 2016-4-29 16:53"
#define DRIVER_VERSION "SD/MMC/SDIO Host Controller Driver(" DRIVER_RIVISION ")" \
			" Compiled in " __DATE__ " at " __TIME__""


#if defined CONFIG_FPGA_V4_PLATFORM || defined CONFIG_FPGA_V7_PLATFORM
#define MMC_FPGA
#endif
//#define USE_OLD_SYS_CLK_INTERFACE


#define SMHC_DEVICE_ID			(2) //number of id in multi device
//max blk count and size is limited by the SMHC_BLK_CFG register's max value
#define MAX_BLK_COUNT		(0xFFFF)
#define MAX_BLK_SIZE		(0x800)
//#define MAX_DES_SIZE		PAGE_SIZE
#define SUNXI_REQ_PAGE_SIZE			(PAGE_SIZE*4)





//-------------------------------------------------------------------------------------
/* registers define */
//--------------------------------------------------------------------------------------
#define SMHC_CMD_ARG2          (0x00)
#define SMHC_BLK_CFG           (0x04)
#define SMHC_CMD_ARG1          (0x08)
#define SMHC_CMD               (0x0C)
#define SMHC_RESP0             (0x10)
#define SMHC_RESP1             (0x14)
#define SMHC_RESP2             (0x18)
#define SMHC_RESP3             (0x1C)
#define SMHC_BUFF              (0x20)
#define SMHC_STA               (0x24)
#define SMHC_CTRL1             (0x28)
#define SMHC_RST_CLK_CTRL      (0x2C)
#define SMHC_INT_STA           (0x30)
#define SMHC_INT_STA_EN        (0x34)
#define SMHC_INT_SIG_EN        (0x38)
#define SMHC_ACMD_ERR_CTRL2    (0x3C)
#define SMHC_SET_ERR           (0x50) 
#define SMHC_ADMA_ERR          (0x54)
#define SMHC_ADMA_ADDR         (0x58)

#define SMHC_CTRL3             (0x200)
#define SMHC_CMD_ATTR          (0x204)
#define SMHC_TO_CTRL2          (0x208)
#define SMHC_ATC               (0x210) 
#define SMHC_RTC               (0x214)
#define SMHC_DITC0             (0x218)
#define SMHC_DITC1             (0x21C)
#define SMHC_TP0               (0x220)
#define SMHC_TP1               (0x224)

#define SMHC_CRC_STA           (0x240)
#define SMHC_TBC0              (0x244)
#define SMHC_TBC1              (0x248)
#define SMHC_BL                (0x24C)
#define SMHC_CEDBN             (0x250)
//--------------------------------------------------------------------------------------

#define smhc_readl(host, reg) \
	__raw_readl((host)->reg_base + reg)
#define smhc_writel(host, reg, value) \
	__raw_writel((value), (host)->reg_base + reg)
#define smhc_readw(host, reg) \
	__raw_readw((host)->reg_base + reg)
#define smhc_writew(host, reg, value) \
	__raw_writew((value), (host)->reg_base + reg)
#define smhc_clr_bit(host, reg, bitmap) \
	do{									\
		u32 tmp = smhc_readl(host,reg);	\
		tmp &= ~(bitmap);				\
		smhc_writel(host,reg,tmp);		\
	}while(0)

#define smhc_set_bit(host, reg, bitmap) \
	do{ 								\
		u32 tmp = smhc_readl(host,reg); \
		tmp |= (bitmap);				\
		smhc_writel(host,reg,tmp);		\
	}while(0)



	/* control register bit field */
	/*0x2c*/
#define ResetAll            (0x1U<<24)
#define ResetCmd            (0x1U<<25)
#define ResetDat            (0x1U<<26)
#define SdclkEn	            (0x1U<<2)
	
	/*0x200*/
#define CPUAcessBuffEn      (0x1U<<31)
#define StopReadClkAtBlkGap (0x1U<<8)
#define SWDebounceMode      (0x1U<<5)
#define DebounceEnb         (0x1U<<4)
#define CdDat3En            (0x1U<<3)
#define SdclkIdleCtrl       (0x1U<<2)
	
	
	/* Struct for SMC Commands */
	/*0x18*/
#define CMDType         (0x3U<<22)
#define DataExp         (0x1U<<21)
#define CheckRspIdx     (0x1U<<20)
#define CheckRspCRC     (0x1U<<19)
#define NoRsp           (0x0U<<16)
#define Rsp136          (0x1U<<16)
#define Rsp48           (0x2U<<16)
#define Rsp48b          (0x3U<<16)
#define SingleBlkTrans  (0x0U<<5)
#define MultiBlkTrans   (0x1U<<5)
#define Read            (0x1U<<4)
#define Write           (0x0U<<4)
#define AutoCmd12       (0x1U<<2)
#define AutoCmd23       (0x2U<<2)
#define BlkCntEn        (0x1U<<1)
#define DMAEn           (0x1U<<0)
	
	/*0x204*/
#define SendInitSeq     (0x1U<<4)
#define DisableBoot     (0x1U<<3)
#define BootACKExp      (0x1U<<2)
#define AltBootMode     (0x2U<<0)
#define MandBootMode    (0x1U<<0)
	
	/*0x03C*/
#define Switch3v3To1v8  (0x1U<<19)
#define DdrType         (0x7<<16)
#define DDR_SHIFT       (16)
	
	/*0x24*/
#define CmdLineSta      (0x1U<<24)
#define Dat3LineSta     (0x1U<<23)
#define Dat2LineSta     (0x1U<<22)
#define Dat1LineSta     (0x1U<<21)
#define Dat0LineSta     (0x1U<<20)
#define WpPinSta        (0x1U<<19)
#define CdPinInvSta     (0x1U<<18)
#define CardStable      (0x1U<<17)
#define CardInsert      (0x1U<<16)
#define BuffRDEn        (0x1U<<11)
#define BuffWREn        (0x1U<<10)
#define RDTransActive   (0x1U<<9)
#define WRTransActive   (0x1U<<8)
#define DatLineActive   (0x1U<<2)
#define CmdInhibitDat   (0x1U<<1)
#define CmdInhibitCmd   (0x1U<<0)
	
	
#define BootDataStart     (0x1U<<29)
#define BootAckRcv        (0x1U<<28)
	//
#define DSFOInt		        (0x1U<<30)
#define DmaErrInt         (0x1U<<25)
#define AcmdErrInt        (0x1U<<24)
#define DatEndBitErrInt   (0x1U<<22)
#define DatCRCErrInt      (0x1U<<21)
#define DatTimeoutErrInt  (0x1U<<20)
#define CmdIdxErrInt      (0x1U<<19)
#define CmdEndBitErrInt   (0x1U<<18)
#define CmdCRCErrInt      (0x1U<<17)
#define CmdTimeoutErrInt  (0x1U<<16)
#define ErrInt            (0x1U<<15)
#define CardInt           (0x1U<<8)
#define CardRemoveInt     (0x1U<<7)
#define CardInsertInt     (0x1U<<6)
#define BuffRDRdyInt      (0x1U<<5)
#define BuffWRRdyInt      (0x1U<<4)
#define DmaInt            (0x1U<<3)
	//#define BlkGapEvtInt		(0x1U<<2)
#define TransOverInt      (0x1U<<1)
#define CmdOverInt        (0x1U<<0)
#define TxDatIntBit       ( DmaInt | TransOverInt | DmaErrInt | ErrInt)
#define RxDatIntBit       ( DmaInt | TransOverInt | DmaErrInt | ErrInt)
#define DmaIntBit         (DmaInt | DmaErrInt)
#define ErrIntBit         (0x437F0000)//(0x1ff<<16)
#define DoneIntBit		  (TransOverInt|CmdOverInt)
	
	//0x28 SMHC_CTRL1 bit field
#define Dma32BitSel       (0x3<<3)
#define DmaSel            (0x3<<3)
#define BusWidth          (0x1<<1)
#define ExtBusWidth       (0x1<<5)
	
	
	/*0x3C Auto CMD Error Status */
#define NoAcmd12          (0x1U<<7)
#define AcmdIdxErr        (0x1U<<4)
#define AcmdEndBitErr     (0x1U<<3)
#define AcmdCRCErr        (0x1U<<2)
#define AcmdTimeoutErr    (0x1U<<1)
#define NotIssueAcmd      (0x0<<0)
	
	

	
enum
{
	ACT_NOP = 0,
	ACT_RSV,
	ACT_TRANS,
	ACT_LINK,
};
	
enum
{
	MAN_BOOT_MD = 0,
	ALT_BOOT_MD,
};
	
	
struct sdhc_idma_des{
	u32 valid			:1, //=1: indicates this line of descriptor is effective. =0: generate ADMA Error interrupt and stop ADMA to prevent runaway.
		end 			:1, //=1: indicates end of descriptor. The Transfer Complete Interrupt is generated when the operation of the descriptor line is completed.
		int_en			:1, //=1: generates DMA Interrupt when the operation of the descriptor line is completed.
						:1,
		act 			:2, //00b: Nop, No Operation, Do not execute current line and go to next line.
							//01b: rsv, reserved, (Same as Nop. Do not execute current line and go to next line.)
							//10b: Tran, transfer data, Transfer data of one descriptor line Transfer data of one descriptor line
							//11b: Link, Link Descriptor, Link to another descriptor
						:10,
		length			:16;
		u32 addr;
};
	
	
struct sunxi_mmc_ctrl_regs {
	u32 rst_clk_ctrl;
	u32 int_sta_en;
	u32 to;
	u32 ctrl3;
	u32 int_sig_en;
	u32 ctrl1;
	u32 acmd_err_ctrl2;
	u32 atc;
};



struct sunxi_mmc_host {
	struct mmc_host	*mmc;
	struct reset_control *reset;

	/* IO mapping base */
	void __iomem	*reg_base;

	/* clock management */
	struct clk	*clk_ahb;
	struct clk	*clk_mmc;
	struct clk	*clk_rst;
	
	int (*sunxi_mmc_clk_set_rate)(struct sunxi_mmc_host *host, struct mmc_ios *ios);

	/* irq */
	spinlock_t	lock;
	int		irq;
	u32		int_sum;
	u32		sdio_imask;

	/* dma */
	u32		idma_des_size_bits;
	dma_addr_t	sg_dma;
	void		*sg_cpu;
	bool		wait_dma;
	u32		dma_tl;
	u64 	dma_mask;

	void (*sunxi_mmc_thld_ctl )(struct sunxi_mmc_host *host,
				  struct mmc_ios *ios, struct mmc_data *data);

	struct mmc_request *mrq;
	struct mmc_request *mrq_busy;
	struct mmc_request *manual_stop_mrq;
	int		ferror;

	u32 	power_on;

	/* pinctrl handles */
	struct pinctrl		*pinctrl;
	struct pinctrl_state	*pins_default;
	struct pinctrl_state	*pins_sleep;

	/*sys node*/
	struct device_attribute maual_insert;
	struct device_attribute *dump_register;
	struct device_attribute dump_clk_dly;
	void (*sunxi_mmc_dump_dly_table)(struct sunxi_mmc_host *host);

	/* backup register structrue */
	struct sunxi_mmc_ctrl_regs bak_regs;
	void (*sunxi_mmc_save_spec_reg)(struct sunxi_mmc_host *host);
	void (*sunxi_mmc_restore_spec_reg)(struct sunxi_mmc_host *host);

	void (*sunxi_mmc_set_acmda)(struct sunxi_mmc_host *host);

	void (*sunxi_mmc_shutdown)(struct platform_device * pdev);

	/*really controller id,no logic id*/
	int phy_index;

	u32  dat3_imask;

	/*no wait busy if wrtie end, only for customer need*/
	#define NO_MANUAL_WAIT_BUSY_WRITE_END  0x1
	#define NO_REINIT_SHUTDOWN			   0x2
	#define CARD_PWR_GPIO_HIGH_ACTIVE	   0x4
	/*control specal function control,for customer need*/
	u32 ctl_spec_cap;

	int card_pwr_gpio;

	void *version_priv_dat;
};


#endif
